package logic.nodes.collision.visibility;

import gameStates.absGamesStates.AbsIngameState;
import gameStates.absGamesStates.gui.AbsHUDState;

import java.util.HashSet;
import java.util.List;

import settings.CheatConfig;

import logic.common.player.Player;
import logic.common.team.Team;
import logic.nodes.TeamNode;
import logic.nodes.collision.CollidableNode;
import logic.nodes.lod.blocks.LeafBlock;
import logic.ships.hunter.Hunter;
import logic.weapons.WeaponFire;
import main.threading.ThreadPoolController;

public class SightController implements ThreadPoolController {
		
	private List<LeafBlock> leafBlocks;
	private int currentIndex;
	private HashSet<CollidableNode> visibleNodes;
	private Team teamA, teamB;
	
	public SightController(List<LeafBlock> leafBlocks, Team teamA, Team teamB) {
		this.leafBlocks = leafBlocks;
		this.teamA = teamA;
		this.teamB = teamB;
		
		visibleNodes = new HashSet<CollidableNode>();
	}
	
	@Override
	public void update(Float time) {
		LeafBlock block = leafBlocks.get(currentIndex);
		assert(block != null);
		
		processTeam(block, teamA);
		processTeam(block, teamB);
		
		currentIndex++;
		if(currentIndex >= leafBlocks.size()) currentIndex = 0;
	}
	
	private void processTeam(LeafBlock block, Team team) {
		visibleNodes.clear();
		Player p = getWatchedPlayer(team);
		boolean isPlayerTeam = p.getTeam() == team;
		boolean checkHunter = isPlayerTeam && p.isAlive() && p.getHunter() != null && p.getHunter().getParent() != null;
		
		for(int i = 0; i < block.getLeafNodes().size(); i++) {
			try {
				CollidableNode leafNode = block.getLeafNodes().get(i);
				if(leafNode == null || leafNode instanceof WeaponFire) continue;
							
				if(checkHunter) processNode(p.getHunter(), leafNode, team);
				if(CheatConfig.get().getSquadSight() && isPlayerTeam && p.getSquad() != null) {
					for(Player member : p.getSquad().getMembers()) {
						if(member == p) continue;
						
						Hunter h = member.getHunter();
						if(h != null && p.isAlive()) processNode(h, leafNode, team);
					}
				}
				
				if(CheatConfig.get().getMotherShipSight() && team.getMotherShip() != null) 
					processNode(team.getMotherShip(), leafNode, team);
				if(CheatConfig.get().getSpawnStationSight()) processNodes(team.getSpawnStations(), leafNode, team);
			} catch(IndexOutOfBoundsException e) {}
		}
	}
	
	private Player getWatchedPlayer(Team team) {
		AbsIngameState ingameState = team.getIngameState();
		AbsHUDState hudState = ingameState.getHUDState();
		if(hudState.isSpectating() && hudState.getWatchedPlayer() != null) return hudState.getWatchedPlayer();
		return ingameState.getPlayer();
	}
	
	private void processNodes(List<? extends TeamNode> nodes, CollidableNode leafNode, Team team) {
		if(visibleNodes.contains(leafNode)) return;
		
		for(int i = 0; i < nodes.size(); i++) {
			processNode(nodes.get(i), leafNode, team);
		}
	}
	
	private void processNode(TeamNode node, CollidableNode leafNode, Team team) {
		if(!visibleNodes.contains(leafNode) && node.allBoundsDone()) {
			boolean vis = node.isInSightSphere(leafNode);
			if(vis) visibleNodes.add(leafNode);
			leafNode.setVisible(vis, team);
		}
	}
}